//////////////////////////////////////////ok
#include"stdafx.h"

#include "bochs.h"



void IA32_CPU::ADD_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2, op1, sum;
	op2 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		sum = op1 + op2;
		write_RMW_virtual_byte(sum);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum, IA32_INSTR_ADD8);
}

void IA32_CPU::ADD_GbEb(Ia32_Instruction_c *i)
{
	Bit8u op1, op2, sum;
	op1 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op2 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2;
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op2);
		sum = op1 + op2;
	}
	IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum, IA32_INSTR_ADD8);
}

void IA32_CPU::ADD_ALIb(Ia32_Instruction_c *i)
{
	Bit8u op1, op2, sum;
	op1 = AL;
	op2 = i->Ib();
	sum = op1 + op2;
	AL = sum;
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum, IA32_INSTR_ADD8);
}

void IA32_CPU::ADC_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2, op1, sum;
	bx_bool temp_CF = getB_CF();
	op2 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2 + temp_CF;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		sum = op1 + op2 + temp_CF;
		write_RMW_virtual_byte(sum);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum,(temp_CF) ? IA32_INSTR_ADC8 : IA32_INSTR_ADD8);
}

void IA32_CPU::ADC_GbEb(Ia32_Instruction_c *i)
{
	Bit8u op1, op2, sum;
	bx_bool temp_CF = getB_CF();
	op1 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op2 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op2);
	}
	sum = op1 + op2 + temp_CF;
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum,(temp_CF) ? IA32_INSTR_ADC8 : IA32_INSTR_ADD8);
	IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
}

void IA32_CPU::ADC_ALIb(Ia32_Instruction_c *i)
{
	Bit8u op1, op2, sum;
	bx_bool temp_CF = getB_CF();
	op1 = AL;
	op2 = i->Ib();
	sum = op1 + op2 + temp_CF;
	AL = sum;
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum,(temp_CF) ? IA32_INSTR_ADC8 : IA32_INSTR_ADD8);
}

void IA32_CPU::SBB_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8, diff_8;
	bx_bool temp_CF = getB_CF();
	op2_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		diff_8 = op1_8 - (op2_8 + temp_CF);
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		diff_8 = op1_8 - (op2_8 + temp_CF);
		write_RMW_virtual_byte(diff_8);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8,(temp_CF) ? IA32_INSTR_SBB8 : IA32_INSTR_SUB8);
}

void IA32_CPU::SBB_GbEb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, op2_8, diff_8;
	bx_bool temp_CF = getB_CF();
	op1_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op2_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op2_8);
	}
	diff_8 = op1_8 - (op2_8 + temp_CF);
	IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8,(temp_CF) ? IA32_INSTR_SBB8 : IA32_INSTR_SUB8);
}

void IA32_CPU::SBB_ALIb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, op2_8, diff_8;
	bx_bool temp_CF = getB_CF();
	op1_8 = AL;
	op2_8 = i->Ib();
	diff_8 = op1_8 - (op2_8 + temp_CF);
	AL = diff_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8,(temp_CF) ? IA32_INSTR_SBB8 : IA32_INSTR_SUB8);
}

void IA32_CPU::SBB_EbIb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8, diff_8;
	bx_bool temp_CF = getB_CF();
	op2_8 = i->Ib();
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		diff_8 = op1_8 - (op2_8 + temp_CF);
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		diff_8 = op1_8 - (op2_8 + temp_CF);
		write_RMW_virtual_byte(diff_8);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8,(temp_CF) ? IA32_INSTR_SBB8 : IA32_INSTR_SUB8);
}

void IA32_CPU::SUB_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8, diff_8;
	op2_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		diff_8 = op1_8 - op2_8;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		diff_8 = op1_8 - op2_8;
		write_RMW_virtual_byte(diff_8);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_SUB8);
}

void IA32_CPU::SUB_GbEb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, op2_8, diff_8;
	op1_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op2_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op2_8);
	}
	diff_8 = op1_8 - op2_8;
	IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_SUB8);
}

void IA32_CPU::SUB_ALIb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, op2_8, diff_8;
	op1_8 = AL;
	op2_8 = i->Ib();
	diff_8 = op1_8 - op2_8;
	AL = diff_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_SUB8);
}

void IA32_CPU::CMP_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8;
	op2_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
	}
#if defined(IA32_HostAsm_Cmp8)
	Bit32u flags32;
	asmCmp8(op1_8, op2_8, flags32);
	IA32_setEFlagsOSZAPC(flags32);
#else
	Bit8u diff_8 = op1_8 - op2_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
#endif
}

void IA32_CPU::CMP_GbEb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, op2_8;
	op1_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op2_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op2_8);
	}
#if defined(IA32_HostAsm_Cmp8)
	Bit32u flags32;
	asmCmp8(op1_8, op2_8, flags32);
	IA32_setEFlagsOSZAPC(flags32);
#else
	Bit8u diff_8 = op1_8 - op2_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
#endif
}

void IA32_CPU::CMP_ALIb(Ia32_Instruction_c *i)
{
	Bit8u op1_8 = AL;
	Bit8u op2_8 = i->Ib();
#if defined(IA32_HostAsm_Cmp8)
	Bit32u flags32;
	asmCmp8(op1_8, op2_8, flags32);
	IA32_setEFlagsOSZAPC(flags32);
#else
	Bit8u diff_8 = op1_8 - op2_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
#endif
}

void IA32_CPU::XADD_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2, op1, sum;
	/* XADD dst(r/m8), src(r8)
	* temp <-- src + dst         | sum = op2 + op1
	* src  <-- dst               | op2 = op1
	* dst  <-- tmp               | op1 = sum
	*/
	op2 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2;
		// and write destination into source
		// Note: if both op1 & op2 are registers, the last one written
		//       should be the sum, as op1 & op2 may be the same register.
		//       For example:  XADD AL, AL
		IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		sum = op1 + op2;
		write_RMW_virtual_byte(sum);
		/* and write destination into source */
		IA32_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum, IA32_INSTR_ADD8);
}

void IA32_CPU::ADD_EbIb(Ia32_Instruction_c *i)
{
	Bit8u op2, op1, sum;
	op2 = i->Ib();
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		sum = op1 + op2;
		write_RMW_virtual_byte(sum);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum, IA32_INSTR_ADD8);
}

void IA32_CPU::ADC_EbIb(Ia32_Instruction_c *i)
{
	Bit8u op2, op1, sum;
	bx_bool temp_CF = getB_CF();
	op2 = i->Ib();
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		sum = op1 + op2 + temp_CF;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		sum = op1 + op2 + temp_CF;
		write_RMW_virtual_byte(sum);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1, op2, sum,(temp_CF) ? IA32_INSTR_ADC8 : IA32_INSTR_ADD8);
}

void IA32_CPU::SUB_EbIb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8, diff_8;
	op2_8 = i->Ib();
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		diff_8 = op1_8 - op2_8;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		diff_8 = op1_8 - op2_8;
		write_RMW_virtual_byte(diff_8);
	}
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_SUB8);
}

void IA32_CPU::CMP_EbIb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8;
	op2_8 = i->Ib();
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
	}
#if defined(IA32_HostAsm_Cmp8)
	Bit32u flags32;
	asmCmp8(op1_8, op2_8, flags32);
	IA32_setEFlagsOSZAPC(flags32);
#else
	Bit8u diff_8 = op1_8 - op2_8;
	IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
#endif
}

void IA32_CPU::NEG_Eb(Ia32_Instruction_c *i)
{
	Bit8u op1_8, diff_8;
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		diff_8 = -op1_8;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		diff_8 = -op1_8;
		write_RMW_virtual_byte(diff_8);
	}
	IA32_SET_FLAGS_OSZAPC_RESULT_8(diff_8, IA32_INSTR_NEG8);
}

void IA32_CPU::INC_Eb(Ia32_Instruction_c *i)
{
	Bit8u op1;
	if (i->modC0()) 
	{
		op1 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		op1++;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1);
		op1++;
		write_RMW_virtual_byte(op1);
	}
	IA32_SET_FLAGS_OSZAP_RESULT_8(op1, IA32_INSTR_INC8);
}

void IA32_CPU::DEC_Eb(Ia32_Instruction_c *i)
{
	Bit8u op1_8;
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
		op1_8--;
		IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
		op1_8--;
		write_RMW_virtual_byte(op1_8);
	}
	IA32_SET_FLAGS_OSZAP_RESULT_8(op1_8, IA32_INSTR_DEC8);
}

void IA32_CPU::CMPXCHG_EbGb(Ia32_Instruction_c *i)
{
	Bit8u op2_8, op1_8, diff_8;
	if (i->modC0()) 
	{
		op1_8 = IA32_READ_8BIT_REGx(i->rm(),i->extend8bitL());
	}
	else 
	{
		read_RMW_virtual_byte(i->seg(), IA32_RMAddr(i), &op1_8);
	}
	diff_8 = AL - op1_8;
	IA32_SET_FLAGS_OSZAPC_8(AL, op1_8, diff_8, IA32_INSTR_COMPARE8);
	if (diff_8 == 0) 
	{  // if accumulator == dest
		// dest <-- src
		op2_8 = IA32_READ_8BIT_REGx(i->nnn(),i->extend8bitL());
		if (i->modC0()) 
		{
			IA32_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op2_8);
		}
		else 
		{
			write_RMW_virtual_byte(op2_8);
		}
	}
	else 
	{
		// accumulator <-- dest
		AL = op1_8;
	}
}
